//
//  PhotoTextureController.m
//  FlutterPluginExp
//
//  Created by BqLin on 2020/10/16.
//  Copyright © 2020 BqLin. All rights reserved.
//

#import "PhotoTextureController.h"
#import "PhotoFrameUpdater.h"
#import <CoreVideo/CoreVideo.h>
#import <libkern/OSAtomic.h>

@interface PhotoTextureController ()

@property (nonatomic, strong) PHAsset *asset;

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, assign) CVPixelBufferRef pixelBuffer;

@end


@implementation PhotoTextureController

- (CVPixelBufferRef)pixelBuffer {
    if (!_pixelBuffer && _image) {
        _pixelBuffer = _pixelBuffer = [self pixelBufferForImage:_image];
    }
    return _pixelBuffer;
}

#pragma mark -

- (instancetype)initWithAsset:(PHAsset *)asset frameUpdater:(PhotoFrameUpdater *)frameUpdater {
    self = [super init];
    if (!self) return nil;
    
    _frameUpdater = frameUpdater;
    _asset = asset;
    
    return self;
}

- (void)requestImage:(PHImageManager *)manager width:(int)width height:(int)height completion:(void (^)(BOOL success))completion {
    PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
    option.networkAccessAllowed = YES;
    option.resizeMode = PHImageRequestOptionsResizeModeExact;
    option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
    
    [manager requestImageForAsset:_asset targetSize:CGSizeMake(width > 0 ? width : CGFLOAT_MAX, height > 0 ? height : CGFLOAT_MAX) contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage *_Nullable image, NSDictionary *_Nullable info) {
        self.image = image;
        if (image) [self imageHandler];
        if (completion) completion(!!image);
    }];
}

- (void)imageHandler {
    //_pixelBuffer = [self pixelBufferForImage:_image];
    
    [self.frameUpdater update];
}

- (CVPixelBufferRef)pixelBufferForImage:(UIImage *)image {
    if (!image) return nil;
    
    CGImageRef imageRef = image.CGImage;
    size_t frameWidth = CGImageGetWidth(imageRef);
    size_t frameHeight = CGImageGetHeight(imageRef);
    // NSDictionary *options =
    // @{
    //     (__bridge NSString *)kCVPixelFormatCGImageCompatibility : @YES,
    //     (__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
    // };
    CVPixelBufferRef pixelBuffer;
    // CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameWidth, frameHeight, kCVPixelFormatType_32BGRA, (__bridge CFDictionaryRef)options, &pixelBuffer);
    // if (status != kCVReturnSuccess) return nil;
    
    CFDictionaryRef empty;
    CFMutableDictionaryRef attrs;
    empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    
    CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
    CVPixelBufferCreate(kCFAllocatorDefault, frameWidth, frameHeight, kCVPixelFormatType_32BGRA, attrs, &pixelBuffer);
    
    CFRelease(empty);
    CFRelease(attrs);
    
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    
    void *dataRef = CVPixelBufferGetBaseAddress(pixelBuffer);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(dataRef, frameWidth, frameHeight, 8, CVPixelBufferGetBytesPerRow(pixelBuffer), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(context, CGRectMake(0, 0, frameWidth, frameHeight), imageRef);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    
    return pixelBuffer;
}

- (void)dispose {
    if (_pixelBuffer) {
        CVBufferRelease(_pixelBuffer);
        _pixelBuffer = NULL;
    };
    _image = nil;
}

- (void)dealloc {
    NSLog(@"%s", __FUNCTION__);
    [self dispose];
}

#pragma mark - FlutterTexture

- (CVPixelBufferRef)copyPixelBuffer {
    //CVBufferRetain(self.pixelBuffer);
    //return _pixelBuffer;
    
    CVPixelBufferRef pixelBuffer = self.pixelBuffer;
    while (!OSAtomicCompareAndSwapPtrBarrier(pixelBuffer, nil, (void **)&_pixelBuffer)) {
        pixelBuffer = _pixelBuffer;
    }
    NSLog(@"%s - %p", __FUNCTION__, pixelBuffer);
    return pixelBuffer;
}

- (void)onTextureUnregistered {
    NSLog(@"%s", __FUNCTION__);
    //dispatch_async(dispatch_get_main_queue(), ^{
        [self dispose];
    //});
}

@end
